package com.commander.spring.cloud.route;

import com.alibaba.cloud.nacos.NacosConfigProperties;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.NacosFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Executor;

/**
 * description:
 * <p>
 * Date: 2020-06-11
 * <p>
 * Time: 18:21
 *
 * @author zhangxin
 */
@Component
public class InitNacosConfigRoute implements CommandLineRunner{
	
	@Value("${spring.application.route-name}")
	private String dataId;
	@Autowired
	private NacosConfigProperties nacosConfigProperties;
	@Autowired
	private ApplicationEventPublisherAwareService routeService;
	private Set<String> routeIds= new HashSet<>();
	
	@Override
	public void run(String... args) throws Exception {
		dynamicRouteByNacosListener();
	}
	
	public void dynamicRouteByNacosListener() throws NacosException {
		ConfigService configService = NacosFactory.createConfigService(nacosConfigProperties.getServerAddr());
		String configRoutes = configService.getConfig(dataId, nacosConfigProperties.getGroup(), 5000);
		initConfigRoutes(configRoutes);
		configService.addListener(dataId, nacosConfigProperties.getGroup(), new Listener() {
			@Override
			public void receiveConfigInfo(String configInfo) {
				updateConfigRoutes(configInfo);
			}
			
			@Override
			public Executor getExecutor() {
				return null;
			}
		});
	}
	
	private void initConfigRoutes(String configRoutes){
		if(StringUtils.isBlank(configRoutes)){
			return;
		}
		
		List<RouteDefinition> gatewayRouteDefinitions = JSON.parseArray(configRoutes, RouteDefinition.class);
		for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {
			routeService.update(routeDefinition);
			
			routeIds.add(routeDefinition.getId());
		}
	}
	
	private void updateConfigRoutes(String configRoutes){
		if(StringUtils.isBlank(configRoutes)){
			return;
		}
		
		Set<String> currentRouteIds = new HashSet<>();
		List<RouteDefinition> gatewayRouteDefinitions = JSON.parseArray(configRoutes, RouteDefinition.class);
		for (RouteDefinition routeDefinition : gatewayRouteDefinitions) {
			routeService.update(routeDefinition);
			
			currentRouteIds.add(routeDefinition.getId());
		}
		
		for(String routeId: routeIds){
			if(currentRouteIds.contains(routeId)){
				continue;
			}
			
			routeService.delete(routeId);
		}
		
		routeIds.clear();
		routeIds.addAll(currentRouteIds);
	}
}
